<?php
pathnode::heritage('filenode',2);
/**
*
* @author J.Ducastel <jducastel@jducastel.fr>
* @version 
*/
class fileNode extends pathNode {
/*------------------------------------------------------------------------------
                                                                     constructor
------------------------------------------------------------------------------*/
    /**
    *
    * @access
    * /
    function filenode($path) {
        $this->__construct($path);
    }/**/
    
    /**
    *
    * @access
    * /
    function __construct($path) {
        parent::__construct($path);
        if (!$this->exists)    {
            touch($path);
        }
    }/**/
/*------------------------------------------------------------------------------
                                                                  public methods
------------------------------------------------------------------------------*/
    /**
    * detects if path applies to self class
    * @param
    * @access public
    * @return bool
    */
    public function selfDetector($path) {
        return is_file($path);
    }/**/
    
    /**
    * read some bytes.
    * Reads all content if bytes is not provided. From offset, if provided, else current offset.
    * @param int bytes optional 1mo by default
    * @param int offset optional uses current offset by default
    * @access public
    * @return mixed file content
    */
    public function read($bytes=1048576, $offset=NULL) {
        /*if (!$this->isReadable()) {
            trigger_error('filenode::read : file'.$this->path.' is not readable',E_USER_NOTICE);
            return false;
        }*/
        // getting handle
        if (!$handle=&$this->handle()) {
            trigger_error('filenode::read could not read '.$this->path);
            return false;
        }
        // setting offset if necessary
        $this->offset($offset);
        return fread($handle,$bytes);
    }/**/
    
    /**
    * write some data.
    * From offset, if provided, else current offset.
    * @param mixed $content
    * @param int offset optional. uses current offset if omitted
    * @access public
    * @return bool
    */
    public function write($content, $offset=NULL) {
        // is file writable
        /*if (!$this->isWritable()) {
            trigger_error('filenode::write : file '.$this->path.' is not writable',E_USER_NOTICE);
            return false;
        }*/
        // getting handle
        if (!$handle=&$this->handle())
            return false;
        // setting offset if necessary
        $this->offset($offset);
        return fwrite($handle,$content);
    }/**/
    
    /**
    * erase from offset
    * @param int offset
    * @return bool
    */
    public function erase($offset=NULL) {
        // getting handle
        if (!$handle=&$this->handle())
            return false;
        // setting offset if necessary
        //$oldOffset=$this->offset();
        $from=$this->offset($offset);
        // echo $from;
        $ok=ftruncate($handle, $from);
        // echo $this->offset();
        // $this->offset($offset);
        return $ok;
    }
    
    /**
    * returns and edventually sets handle’s offset.
    * @param int offset optional sets new offset
    * @access public
    * @return int current offset
    */
    public function offset($offset=NULL,$whence=NULL) {
        // getting file handle
        if (!$handle=&$this->handle())
            return false;
        // is new offset provided
        if (is_int($offset)) {
            // setting whence 
            switch ($whence) {
                case SEEK_CUR: // new offset is from current position
                case SEEK_END: // new offset is from the end
                    break;
                default: // new offset is from start
                    $whence=SEEK_SET;
            }
            // trying to set new offset
            fseek($handle,$offset,$whence);
        }
        return ftell($handle);
    }/**/
    
    /**
    * sets offset to end of file
    */
    public function toEnd() {
        return $this->offset(0,SEEK_END);
    }
    /**
    * sets offset to start of file
    */
    public function toStart() {
        return $this->offset(0,SEEK_SET);
    }
    
    /**
    * destroy file
    * @param
    * @access public
    * @return 
    */
    public function delete() {
        if (!$this->exists) return true;
        $this->exists=!unlink($this->path);
        return !$this->exists;
    }/**/
    
    /**
    * 
    * @param
    * @access public
    * @return 
    * /
    public function move($path) {
        
    }/**/
    
    /**
    * 
    * @param
    * @access public
    * @return int
    */
    public function size() {
        return $this->exists()?filesize($this->path):0;
    }/**/
    
    /**
    * does the file exists ?
    * @param
    * @access public
    * @return bool
    */
    public function exists() {
        return file_exists($this->path);
    }/**/
    
    /**
    * returns md5 hash of the file's content
    * @param
    * @access public
    * @return 
    */
    public function md5() {
        return md5_file($this->path);
    }/**/
    
    /**
    * is the file readable ?
    * @access public
    * @return bool
    */
    public function isReadable() {
        if (PHP_OS=='WINNT')
            return true;
        //clearstatcache();
        return is_readable($this->path);
    }/**/
    
    /**
    * 
    * @param
    * @access public
    * @return 
    */
    public function isWritable() {
        if (PHP_OS=='WINNT')
            return true;
        return is_writable($this->path);
    }/**/
    
    /**
    * executes a regex search on self name, returns results array
    * @param
    * @access public
    * @return array
    */
    public function regexSelfName($regex) {
        if (!ereg($regex,$this->basename,$results))
            return false;
        return $results;
    }/**/
    
    /**
    * 
    * @param
    * @access public
    * @return 
    * /
    function () {
        
    }/**/
    

/*------------------------------------------------------------------------------
                                                                      properties
------------------------------------------------------------------------------*/
    /**
    * @var type desc
    */
    //var $type='file';
    protected $_handle; // file's handle
    protected $mode; // handle's mode
    protected $_offset=0; // handler position, in octets since start
    // var $_mode; // current fopen mode
    // var $content; // file content 
    // var $size;
    //var $_sync=false;
    // var $_sync_mode=false; // if file content has to be saved/read every time
/*------------------------------------------------------------------------------
                                                               protected methods
------------------------------------------------------------------------------*/
    /**
    * 
    * @param
    * @access protected
    * @return 
    * /
    function setInfo($path) {
        parent::setinfo($path);
        if ($this->exists) 
            $this->size=filesize($this->relative_path);
        else
            $this->size=0;
    }/**/
    
    /**
    * returns file handle
    * @access public
    * @param string $mode
    * @return resource file hande
    */
    protected function & handle($mode=null) {
        if (!$this->_handle) {
            // defining default mode if required
            if (is_null($mode)) {
                switch (true) {
                    case $this->exists() and $this->isWritable():
                        $mode='r+';
                        break;
                    case $this->exists():
                        $mode='r';
                        break;
                    default:
                        $mode='w+';
                }
            }
            // opening in requested mode
            if ($this->_handle=fopen($this->path,$mode)) {
                $this->mode=$mode;
                // trigger_error('opened '.$this->path.' in mode '.$mode);
            } else
                trigger_error('failed to open '.$this->path.' in mode '.$mode);
            // echo wakapi::vardump($this);
        }
        return $this->_handle;
    }/**/
    

    
    /**
    * return file's handle
    * @param
    * @access public
    * @return 
    * /
    function & _getHandle($rewind=false) {
        if ($rewind)
            $this->_closeHandle();
        if (!$this->_handle) {
            if ($this->exists)
                $this->_handle=fopen($this->path,'r+');
            else
                $this->_handle=fopen($this->path,'w+');
        }
        return $this->_handle;
    }/**/
    
    /**
    * 
    * @param
    * @access public
    * @return 
    * /
    function () {
        
    }/**/
}
?>
